package semantic;

import parser.ASTNode;
import parser.NodeType;
import lexer.TokenType;
import java.util.List;

public class SemanticAnalyzer {
    private SymbolTable symbolTable;

    public SemanticAnalyzer() {
        this.symbolTable = new SymbolTable();
        initializeBuiltInSymbols();
    }

    // 初始化通达信内置变量和函数
    private void initializeBuiltInSymbols() {
        // 通达信内置变量（行情数据）
        symbolTable.define("OPEN", null);      // 开盘价
        symbolTable.define("HIGH", null);      // 最高价
        symbolTable.define("LOW", null);       // 最低价
        symbolTable.define("CLOSE", null);     // 收盘价
        symbolTable.define("VOL", null);       // 成交量
        symbolTable.define("AMOUNT", null);    // 成交额
        symbolTable.define("DATE", null);      // 日期
        symbolTable.define("TIME", null);      // 时间

        // 通达信内置技术指标函数
        symbolTable.define("MA", null);        // 移动平均线
        symbolTable.define("EMA", null);       // 指数移动平均
        symbolTable.define("MACD", null);      // MACD指标
        symbolTable.define("KDJ", null);       // KDJ指标
        symbolTable.define("RSI", null);       // RSI指标
        symbolTable.define("BOLL", null);      // 布林带
        symbolTable.define("CROSS", null);     // 交叉函数
        symbolTable.define("REF", null);       // 引用若干周期前的数据
        symbolTable.define("HHV", null);       // 最高值
        symbolTable.define("LLV", null);       // 最低值
        symbolTable.define("SUM", null);       // 求和
        symbolTable.define("COUNT", null);     // 统计

        // 通达信内置逻辑函数
        symbolTable.define("IF", null);        // 条件函数
        symbolTable.define("AND", null);       // 逻辑与
        symbolTable.define("OR", null);        // 逻辑或
        symbolTable.define("NOT", null);       // 逻辑非

        // 通达信内置数学函数
        symbolTable.define("ABS", null);       // 绝对值
        symbolTable.define("MAX", null);       // 最大值
        symbolTable.define("MIN", null);       // 最小值
        symbolTable.define("SQRT", null);      // 平方根
        symbolTable.define("POW", null);       // 幂运算
        symbolTable.define("LN", null);        // 自然对数
        symbolTable.define("LOG", null);       // 常用对数
        symbolTable.define("SIN", null);       // 正弦
        symbolTable.define("COS", null);       // 余弦
        symbolTable.define("TAN", null);       // 正切
    }

    public void analyze(ASTNode node) {
        switch (node.getType()) {
            case PROGRAM:
                analyzeProgram(node);
                break;
            case ASSIGNMENT_STATEMENT:
                analyzeAssignment(node);
                break;
            case VARIABLE:
                analyzeVariable(node);
                break;
            case FUNCTION_CALL:
                analyzeFunctionCall(node);
                break;
            case IF_STATEMENT:
                analyzeIfStatement(node);
                break;
            case FOR_LOOP:
                analyzeForLoop(node);
                break;
            case WHILE_LOOP:
                analyzeWhileLoop(node);
                break;
            case BINARY_OPERATION:
                analyzeBinaryOperation(node);
                break;
            case UNARY_OPERATION:
                analyzeUnaryOperation(node);
                break;
            default:
                // 递归分析所有子节点
                for (ASTNode child : node.getChildren()) {
                    analyze(child);
                }
                break;
        }
    }

    private void analyzeProgram(ASTNode node) {
        for (ASTNode child : node.getChildren()) {
            analyze(child);
        }
    }

    private void analyzeAssignment(ASTNode node) {
        // 检查左侧是否是有效的标识符
        String varName = node.getToken().getValue();

        // 分析右侧表达式
        if (node.getChildren().size() > 0) {
            analyze(node.getChildren().get(0));
        }

        // 将变量添加到符号表（如果是用户定义的变量）
        if (!isBuiltInVariable(varName) && !isBuiltInFunction(varName)) {
            symbolTable.define(varName, null);
        } else {
            throw new RuntimeException("Semantic error: cannot assign to built-in symbol '" + varName + "'");
        }
    }

    private void analyzeVariable(ASTNode node) {
        String varName = node.getToken().getValue();

        // 检查是否是内置变量或已定义的变量
        if (!symbolTable.exists(varName) && !isBuiltInVariable(varName)) {
            throw new RuntimeException("Semantic error: undefined variable '" + varName + "'");
        }
    }

    private void analyzeFunctionCall(ASTNode node) {
        String funcName = node.getToken().getValue();

        // 检查是否是内置函数
        if (!isBuiltInFunction(funcName) && !symbolTable.exists(funcName)) {
            throw new RuntimeException("Semantic error: undefined function '" + funcName + "'");
        }

        // 检查参数
        for (ASTNode arg : node.getChildren()) {
            analyze(arg);
        }

        // 这里可以添加特定函数的参数检查
        checkFunctionParameters(funcName, node.getChildren().size());
    }

    private void checkFunctionParameters(String funcName, int paramCount) {
        // 根据函数名检查参数数量
        switch (funcName) {
            case "MA":
            case "EMA":
                if (paramCount < 2) {
                    throw new RuntimeException("Semantic error: function " + funcName + " requires at least 2 parameters");
                }
                break;
            case "CROSS":
                if (paramCount != 2) {
                    throw new RuntimeException("Semantic error: function CROSS requires exactly 2 parameters");
                }
                break;
            case "IF":
                if (paramCount != 3) {
                    throw new RuntimeException("Semantic error: function IF requires exactly 3 parameters");
                }
                break;
            // 可以添加更多函数的参数检查
        }
    }

    private boolean isBuiltInVariable(String name) {
        // 通达信内置变量列表
        String[] builtInVars = {"OPEN", "HIGH", "LOW", "CLOSE", "VOL", "AMOUNT", "DATE", "TIME"};
        for (String var : builtInVars) {
            if (var.equals(name)) {
                return true;
            }
        }
        return false;
    }

    private boolean isBuiltInFunction(String name) {
        // 通达信内置函数列表
        String[] builtInFuncs = {
                "MA", "EMA", "MACD", "KDJ", "RSI", "BOLL", "CROSS", "REF",
                "HHV", "LLV", "SUM", "COUNT", "IF", "AND", "OR", "NOT",
                "ABS", "MAX", "MIN", "SQRT", "POW", "LN", "LOG", "SIN", "COS", "TAN"
        };
        for (String func : builtInFuncs) {
            if (func.equals(name)) {
                return true;
            }
        }
        return false;
    }

    private void analyzeIfStatement(ASTNode node) {
        List<ASTNode> children = node.getChildren();
        if (children.size() < 2) {
            throw new RuntimeException("Semantic error: if statement requires at least condition and then branch");
        }

        // 检查条件表达式类型
        analyze(children.get(0));

        // 检查then分支
        analyze(children.get(1));

        // 检查else分支（如果有）
        if (children.size() > 2) {
            analyze(children.get(2));
        }
    }

    private void analyzeForLoop(ASTNode node) {
        List<ASTNode> children = node.getChildren();
        if (children.size() < 3) {
            throw new RuntimeException("Semantic error: for loop requires variable, start, end and body");
        }

        // 分析循环变量和范围
        analyze(children.get(0)); // start
        analyze(children.get(1)); // end
        if (children.size() > 3) {
            analyze(children.get(2)); // step
        }

        // 分析循环体
        analyze(children.get(children.size() - 1));
    }

    private void analyzeWhileLoop(ASTNode node) {
        List<ASTNode> children = node.getChildren();
        if (children.size() < 2) {
            throw new RuntimeException("Semantic error: while loop requires condition and body");
        }

        analyze(children.get(0)); // condition
        analyze(children.get(1)); // body
    }

    private void analyzeBinaryOperation(ASTNode node) {
        TokenType opType = node.getToken().getType();
        List<ASTNode> children = node.getChildren();

        if (children.size() != 2) {
            throw new RuntimeException("Semantic error: binary operation requires exactly two operands");
        }

        analyze(children.get(0));
        analyze(children.get(1));

        // 这里可以添加类型检查逻辑
    }

    private void analyzeUnaryOperation(ASTNode node) {
        TokenType opType = node.getToken().getType();
        List<ASTNode> children = node.getChildren();

        if (children.size() != 1) {
            throw new RuntimeException("Semantic error: unary operation requires exactly one operand");
        }

        analyze(children.get(0));

        // 这里可以添加类型检查逻辑
    }

    public SymbolTable getSymbolTable() {
        return symbolTable;
    }
}